package com.ezops.poc.validations.validators;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import com.ezops.poc.validations.result.FieldValidationError;
import com.ezops.poc.validations.result.ValidationResult;

/**
 * Checks if the type of the field being under test matches the expected format
 * or not.
 * 
 * @author vgaurav
 * 
 */
public class TypeValidator implements IValidators {

	private  String fieldName;
	private  String requiredType;

	public TypeValidator() {
		
	}

	/*
	 * Mapping betweeb primitive and Wrapper class.
	 */
	private static Map<String, Class> primitiveMap = new HashMap<String, Class>();

	static {
		primitiveMap.put("boolean", Boolean.class);
		primitiveMap.put("byte", Byte.class);
		primitiveMap.put("character", Character.class);
		primitiveMap.put("Short", Short.class);
		primitiveMap.put("integer", Integer.class);
		primitiveMap.put("long", Long.class);
		primitiveMap.put("float", Float.class);
		primitiveMap.put("double", Double.class);
		primitiveMap.put("string", String.class);
	}

	public ValidationResult validate(Object model) {
		if (model == null) {
			throw new IllegalArgumentException("Can't not validate null model");
		}
		
		if("string".equals(requiredType.toLowerCase())){
			return ValidationResult.getValidResponse();
		}
		final Object value;

		try {
			final Field field = model.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);
			value = field.get(model);

			Class destinationClass = primitiveMap.get(requiredType.toLowerCase());

			Method m = destinationClass.getMethod("valueOf", String.class);
			int mods = m.getModifiers();
			if (Modifier.isStatic(mods) && Modifier.isPublic(mods)) {
				m.invoke(null, value);
			}
			// control reaches here that means its convertible.
			return ValidationResult.getValidResponse();

		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// TODO
		return ValidationResult.getErrorResponse(new FieldValidationError() {

			public String getFieldName() {
				return fieldName;
			}

			public String getErrorMessage() {
				return "The Data is not in required type. Expected "
						+ requiredType;
			}
		});
	}

	public void init(String fieldName, String... values) {
		this.fieldName = fieldName;
		this.requiredType = values[0];
	}
}
